package com.ar.engine.common;

import android.opengl.GLES20;
import android.util.Log;

public class ShaderManager {
	
	public static final String vShaderStr()
	{
		String vShaderStr =
	        "uniform mat4 u_mvpMatrix;    				\n"
	      + "attribute vec4 a_position;   				\n"
	      + "attribute vec2 a_texCoord;   				\n"
	      + "varying vec2 v_texCoord;     				\n"
	      + "void main()                  				\n"
	      + "{                            				\n"
	      + "   gl_Position = u_mvpMatrix * a_position; \n"
	      + "   v_texCoord = a_texCoord;  				\n"
	      + "}     										\n";
		
		String VertexShader = 
				"uniform mat4 u_mvpMatrix;      \n"		// A constant representing the combined model/view/projection matrix.
			  + "uniform mat4 u_MVMatrix;       \n"		// A constant representing the combined model/view matrix.
			  			
			  + "attribute vec4 a_position;     \n"		// Per-vertex position information we will pass in.
			  + "attribute vec2 a_texCoord;     \n"		// Per-vertex color information we will pass in.
			  + "attribute vec3 a_Normal;       \n"		// Per-vertex normal information we will pass in.
			  
			  + "varying vec4 v_Position;       \n"		// This will be passed into the fragment shader.
			  + "varying vec2 v_texCoord;       \n"		// This will be passed into the fragment shader.
			  + "varying vec3 v_Normal;         \n"		// This will be passed into the fragment shader.
			  
			// The entry point for our vertex shader.  
			  + "void main()                                                \n" 	
			  + "{                                                          \n"
			// Transform the vertex into eye space.
			  + "   v_Position = vec4(u_MVMatrix * a_Position);             \n"
			// Pass through the color.
			  + "   v_texCoord = a_texCoord;                                \n"
			// Transform the normal's orientation into eye space.
			  + "   v_Normal = vec3(u_MVMatrix * vec4(a_Normal, 0.0));      \n"
			// gl_Position is a special variable used to store the final position.
			// Multiply the vertex by the matrix to get the final point in normalized screen coordinates.
			  + "   gl_Position = u_mvpMatrix * a_position;                 \n"      		  
			  + "}                                                          \n";      

		return VertexShader;
	}
	
	public static final String fShaderStr()
	{
		String fShaderStr = 
	        "precision mediump float;                            						\n"
			
		  +	"uniform vec3 u_LightPos; 													\n"
		  
	      + "varying vec2 v_texCoord;                            						\n"
	      + "uniform sampler2D s_texture;                        						\n"
	      + "varying vec4 v_Position; 													\n"
	      + "varying vec3 v_Normal;														\n"						
	      + "void main()                                         						\n"
	      + "{                                                   						\n"
	      + "	float distance = length(u_LightPos - v_Position);						\n"
	      + " 	vec3 lightVector = normalize(u_LightPos - v_Position);					\n"
	      + " 	float diffuse = max(dot(v_Normal, lightVector), 0.1);					\n"
	      + "	diffuse = diffuse * (1.0/ (1.0 + ( 0.25 * distance * distance)));		\n"
	      + "	gl_FragColor = texture2D(s_texture, v_texCoord) * diffuse; 				\n" 
	      + "} 													 						\n";
		
		return fShaderStr;
	}
	
	                       				
	
	public static final String VertexShader = 
		"uniform mat4 uMVPMatrix;\n" +
        "attribute vec4 aPosition;\n" +
        "attribute vec2 aTextureCoord;\n" +
        "varying vec2 vTextureCoord;\n" +
        "void main() {\n" +
        "  gl_Position = uMVPMatrix * aPosition;\n" +
        "  vTextureCoord = aTextureCoord;\n" +
        "}\n";
	
	public static final String FragmentShader = 
		"precision mediump float;\n" +
        "varying vec2 vTextureCoord;\n" +
        "uniform sampler2D sTexture;\n" +
        "void main() {\n" +
        "  gl_FragColor = texture2D(sTexture, vTextureCoord);\n" +
        "}\n";

	private static String TAG = "AR ENGINE";
	
	 public static int createProgram(String vertexSource, String fragmentSource) {
	        int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexSource);
	        if (vertexShader == 0) {
	        	Log.e("VERTEX SHADER ERROR!", "THIS IS VERTEX SHADER ERROR!");
	            return 0;
	        }

	        int pixelShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentSource);
	        if (pixelShader == 0) {
	        	Log.e("FRAGMENT SHADER ERROR!", "THIS IS FRAGMENT SHADER ERROR!");
	            return 0;
	        }

	        int program = GLES20.glCreateProgram();
	        if (program != 0) {
	            GLES20.glAttachShader(program, vertexShader);
	            checkGlError("glAttachShader");
	            GLES20.glAttachShader(program, pixelShader);
	            checkGlError("glAttachShader");
	            GLES20.glLinkProgram(program);
	            int[] linkStatus = new int[1];
	            GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, linkStatus, 0);
	            if (linkStatus[0] != GLES20.GL_TRUE) {
	                Log.e(TAG, "Could not link program: ");
	                Log.e(TAG, GLES20.glGetProgramInfoLog(program));
	                GLES20.glDeleteProgram(program);
	                program = 0;
	            }
	        }
	        return program;
	    }
	 
	 public static int loadShader(int shaderType, String source) {
	        int shader = GLES20.glCreateShader(shaderType);
	        if (shader != 0) {
	            GLES20.glShaderSource(shader, source);
	            GLES20.glCompileShader(shader);
	            int[] compiled = new int[1];
	            GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compiled, 0);
	            if (compiled[0] == 0) {
	                Log.e(TAG, "Could not compile shader " + shaderType + ":");
	                Log.e(TAG, GLES20.glGetShaderInfoLog(shader));
	                GLES20.glDeleteShader(shader);
	                shader = 0;
	            }
	        }
	        return shader;
	    }
	 
	 public static void checkGlError(String op) {
	        int error;
	        while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) {
	            Log.e(TAG, op + ": glError " + error);
	            throw new RuntimeException(op + ": glError " + error);
	        }
	 }
}
